package com.hifar.common;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hifar.fw.utils.lang.NumberUtils;
import com.hifar.model.VO.QueryParam;
import com.hifar.model.VO.QueryParamsVO;
import com.hifar.model.VO.SortParam;
import com.hifar.utils.ToolKit;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author zhuWeiWei
 * @description 生成queryParam
 * @date 2024/12/27 9:46
 */
public class QueryParamBean<T> {
    private QueryParamsVO queryParams;

    private List<String> fields;

    private QueryWrapper<T> queryWrapper;

    public <T> QueryParamBean(QueryParamsVO queryParams) {
        this.queryParams = queryParams;
        queryWrapper = new QueryWrapper<>();
        fields = new ArrayList<>();
    }

    public <T> QueryParamBean(QueryParamsVO queryParams, Class clazz) {
        this.queryParams = queryParams;
        queryWrapper = new QueryWrapper<>();
        fields = new ArrayList<>();
        this.addColumns(clazz);
    }

    public void addColumns(Class tableClass, String tablePre) {
        boolean isPreTable = StringUtils.hasText(tablePre);
        Annotation annotation = tableClass.getAnnotation(TableName.class);
        Assert.notNull(annotation, tableClass.getCanonicalName() + "不存在TableName注解");
        List<Field> fields = getAllFields(tableClass);
        for (Field field : fields) {
            TableField tableField = field.getAnnotation(TableField.class);
            TableLogic tableLogicField = field.getAnnotation(TableLogic.class);
            if (Objects.nonNull(tableLogicField)) {
                String columnName = tableField.value();
                if (!StringUtils.hasText(columnName)) {
                    String fieldName = field.getName();
                    columnName = ToolKit.toUnderScoreCase(fieldName);
                }

                if (isPreTable) {
                    queryWrapper.eq(tablePre + "." + columnName, "0");
                } else {
                    queryWrapper.eq(columnName, "0");
                }
            }

            if (Objects.nonNull(tableField)) {
                boolean exist = tableField.exist();
                if (exist) {
                    String columnName = tableField.value();
                    if (!StringUtils.hasText(columnName)) {
                        String fieldName = field.getName();
                        columnName = ToolKit.toUnderScoreCase(fieldName);
                    }
                    this.fields.add(isPreTable ? tablePre + "." + columnName : columnName);
                }
            } else {
                String fieldName = field.getName();
                String columnName = ToolKit.toUnderScoreCase(fieldName);
                this.fields.add(isPreTable ? tablePre + "." + columnName : columnName);
            }
        }
    }

    public void addColumns(Class tableClass) {
        this.addColumns(tableClass, "");
    }

    public void addColumns(String tableName, String tablePre) {
        // TODO: 待实现
    }

    public void addColumns(String tableName) {
        // TODO: 待实现
    }

    public void addField(String fieldName) {
        this.fields.add(ToolKit.toUnderScoreCase(fieldName));
    }

    public void addField(String fieldName, String tablePre) {
        this.fields.add(tablePre + "." + ToolKit.toUnderScoreCase(fieldName));
    }

    public Page<T> getPage() {
        if (Objects.isNull(queryParams)) {
            return new Page<T>(1, 20);
        }
        Integer pageNo = NumberUtils.parseInt(queryParams.getPageNo(), 0);
        Integer pageSize = NumberUtils.parseInt(queryParams.getPageSize(), 20);
        return new Page<>(pageNo, pageSize);
    }


    public QueryWrapper<T> getQueryWrapper() {
        if (Objects.isNull(queryParams)) {
            return queryWrapper;
        }
        List<QueryParam> queryParamList = queryParams.getQueryParam();
        if (Objects.isNull(queryParamList)) {
            return queryWrapper;
        }
        for (QueryParam queryParam : queryParamList) {
            String key = queryParam.getKey();
            Object value = queryParam.getValue();
            if (Objects.isNull(value)) {
                continue;
            }
            String columnName = ToolKit.toUnderScoreCase(key);
            this.fields.stream().filter(itemKey -> {
                String[] keyArr = itemKey.split("\\.");
                if (keyArr.length > 1) {
                    return Objects.equals(columnName, keyArr[1].toLowerCase(Locale.ROOT));
                }
                return Objects.equals(columnName, itemKey.toLowerCase(Locale.ROOT));
            }).findFirst()
                    .ifPresent(field -> {
                        this.conditionParam(queryParam, field);
                    });
        }

        List<SortParam> sortParamList = Optional.ofNullable(queryParams.getSortParam()).orElse(new ArrayList<>());
        for (SortParam sortParam : sortParamList) {
            String key = sortParam.getKey();
            Integer value = sortParam.getValue();
            if (Objects.isNull(value)) {
                continue;
            }
            String columnName = ToolKit.toUnderScoreCase(key);

            this.fields.stream().filter(itemKey -> {
                String[] keyArr = itemKey.split("\\.");
                if (keyArr.length > 1) {
                    return Objects.equals(columnName, keyArr[1].toLowerCase(Locale.ROOT));
                }
                return Objects.equals(columnName, itemKey.toLowerCase(Locale.ROOT));
            }).findFirst()
                    .ifPresent(field -> {
                        if (value == 3) {
                            queryWrapper.orderByDesc(field);
                        } else {
                            queryWrapper.orderByAsc(field);
                        }
                    });
        }
        return queryWrapper;
    }


    private void conditionParam(QueryParam queryParam, String field) {
        String matchType = queryParam.getMatchType();
        if (Objects.isNull(matchType)) {
            return;
        }

        Object value = queryParam.getValue();
        String key = queryParam.getKey();
        switch (matchType) {
            case "equal":
                queryWrapper.eq(field, value);
                break;
            case "notEqual":
                queryWrapper.ne(field, value);
                break;
            case "greaterThan":
                queryWrapper.gt(field, value);
                break;
            case "greaterThanEqual":
                queryWrapper.ge(field, value);
                break;
            case "lessThan":
                queryWrapper.lt(field, value);
                break;
            case "lessThanEqual":
                queryWrapper.le(field, value);
                break;
            case "contain":
                queryWrapper.like(field, value);
                break;
            case "notContain":
                queryWrapper.notLike(field, value);
                break;
            case "list":
                queryWrapper.in(field, value);
                break;
            case "notList":
                queryWrapper.notIn(field, value);
            case "range":
                if (value instanceof List) {
                    List<String> valueList = (List) value;
                    if (valueList.size() == 2) {
                        queryWrapper.and(item -> item.ge(field, valueList.get(0).toString()));
                        queryWrapper.and(item -> item.le(field, valueList.get(1).toString()));
                    }
                }
                break;
            default:
                break;
        }
    }

    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        // 递归获取所有父类的字段
        for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
            Field[] declaredFields = c.getDeclaredFields();
            for (Field field : declaredFields) {
                fields.add(field);
            }
        }
        return fields;
    }


}
